/* 
* Copyright (C) 2005, 2006 Liu Di <liudidi@gmail.com> 
*
* Copyright (C) 2007 Wei Lian <lianwei3@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "sopfork.h"
#include "header.h"
#include "playfork.h"
#include "utils.h"
#include "tabwidget.h"
#include "pageplay.h"
#include "mystatusbar.h"
#include "record.h"
#include "mainwindow.h"

SopFork::SopFork (QWidget * widget, QString url, QString name, QString type,
		  QWidget * parent, const char *name2):
QObject (parent, name2),
channelurl (url),
channelname (name),
channeltype (type),
tabwidget (static_cast < TabWidget * >(parent))
{
   ///sop process
   sop = new QProcess (this);
   connect (sop, SIGNAL (readyReadStdout ()), this, SLOT (parseStdout ()));
   connect (sop, SIGNAL (processExited ()), this, SLOT (onSopExit ()));
   ///timer
   echotimer = new QTimer (this);
   connect (echotimer, SIGNAL (timeout ()), this, SLOT (echo ()));
   ///socket notifier
   snstatus = NULL;
   ///append widget to listpage
   listpage.append (widget);
   ///update message
   message = tr ("Connecting...");
   ///fork sop 
   forkSop ();
}


SopFork::~SopFork ()
{
   if (snstatus)
      delete snstatus;
   killSop ();
}


////fork new process
bool
SopFork::forkSop ()
{
   ///select inport and outport number
   int i, j, sock;
   while (1) {
      i = rand () % (65536 - 10000) + 10000;	////10000 to 65535
      sock = connect_to_server ("127.0.0.1", i);
      if (sock == -1)
	 break;
      else if (sock >= 0)
	 ::close (sock);
   }
   sprintf (inport, "%d", i);
   while (1) {
      j = rand () % (65536 - 10000) + 10000;
      sock = connect_to_server ("127.0.0.1", j);
      if (sock == -1 && j != i)
	 break;
      else if (sock >= 0)
	 ::close (sock);
   }
   sprintf (outport, "%d", j);
   ////fork sop process    
   sop->clearArguments ();
   sop->addArgument ("sp-sc");
   sop->addArgument (channelurl);
   sop->addArgument (inport);
   sop->addArgument (outport);
   return sop->start ();
}



////kill process
void
SopFork::killSop ()
{
/*    if (sop->isRunning()) {
//      sop->tryTerminate ();
	sop->kill();
    }*/
   char sopUrl[128] = "sp-sc ";
   strcat (sopUrl, channelurl.ascii ());
   strcat (sopUrl, " ");
   strcat (sopUrl, inport);
   strcat (sopUrl, " ");
   strcat (sopUrl, outport);
   killProcess (sopUrl, sop->processIdentifier (),
		sop->processIdentifier () + 10);

}



/////////////slots
void
SopFork::onSopExit ()
{
   ///restart sop
   if (forkSop ()) {
   }
   else
      fprintf (stderr, "failed to launch sp-sc!\n");
}


void
SopFork::parseStdout ()
{
   QString str = QString (sop->readStdout ());

   if (snstatus == 0) {
      if (str.contains ("hook_sc") || str.contains ("downloadRate=")) {
	 //create socket
	 int sockfd = connect_to_server ("127.0.0.1", atoi (outport));
	 if (sockfd < 0) {
	    fprintf (stderr,
		     "failed to create socket, return err %d\n", sockfd);
	    return;
	 }
	 ///bind QSocketNotifier to socket
	 snstatus = new QSocketNotifier (sockfd, QSocketNotifier::Read, this);
	 connect (snstatus, SIGNAL (activated (int)),
		  SLOT (streamReady (int)));
	 write (sockfd, "state\ns\n", sizeof ("state\ns\n"));
	 write (sockfd, "state\ns\n", sizeof ("state\ns\n"));
	 ///launch player, should be executed after registering snstatus
	 for (QWidget * wd = listpage.first (); wd; wd = listpage.next ())
	    if (static_cast < MyHBox * >(wd)->pagetype == "play"
		&& static_cast < PagePlay * >(wd)->buttonplayer->isOn ())
	       static_cast < PagePlay * >(wd)->onButtonPlayerToggled (true);
	 ///update message
	 message = "data";
      }
      else if (str.contains ("detect MTU")) {
	 ///update message
	 message = tr ("Waiting...");
	 ///show message on statusbar
	 for (QWidget * wd = listpage.first (); wd; wd = listpage.next ())
	    if (tabwidget->indexOf (wd) == tabwidget->currentPageIndex ()) {
	       static_cast < MainWindow * >(qApp->mainWidget ())
		  ->statusbar->showMessage (message);
	       break;
	    }
      }
   }
}


void
SopFork::streamReady (int fd)
{
   char buff[64];
   memset (buff, 0, sizeof (buff));

   int red = 0, size, ret;
   size = sizeof (buff);
   while (1) {
      ret =::read (fd, buff + red, size);
      if (ret <= 0)		///server shutdown
      {
	 if (ret < 0)
	    perror ("status socketnotifier");
	 //close socket and delete socket noitifier
	 ::close (fd);
	 delete snstatus;
	 snstatus = 0;
	 ///stop timer
	 echotimer->stop ();
	 ///change statusbar interface
	 ///update message
	 message = tr ("Connecting...");
	 ///show message on statusbar
	 for (QWidget * wd = listpage.first (); wd; wd = listpage.next ())
	    if (tabwidget->indexOf (wd) == tabwidget->currentPageIndex ()) {
	       static_cast < MainWindow * >(qApp->mainWidget ())
		  ->statusbar->showMessage (message);
	       break;
	    }
	 ///
	 return;
      }
      if (strstr (buff, "\n"))
	 break;

      red += ret;
      size -= ret;
   }

   if (buff[0] != 10) {
      char *savept;
      ::strtok_r (buff, "\n", &savept);

      int value[6];
      value[0] = atoi (strtok_r (buff, " ", &savept));
      for (int i = 1; i < 6; i++) {
	 value[i] = atoi (strtok_r (NULL, " ", &savept));
	 if (i < 5)
	    value[i] = value[i] / 1024;
      }

      static const char format[][10] =
	 { "%d%%", "ur=%dk", "dr=%dk", "us=%dk", "ds=%dk", "peers=%d" };

      for (int i = 0; i < 6; i++) {
	 sprintf (buff, format[i], value[i]);
	 arraymessage[i] = buff;
      }
      ///show arraymessage on statusbar
      for (QWidget * wd = listpage.first (); wd; wd = listpage.next ())
	 if (tabwidget->indexOf (wd) == tabwidget->currentPageIndex ()) {
	    static_cast < MainWindow * >(qApp->mainWidget ())
	       ->statusbar->showMessage (arraymessage);
	    break;
	 }
   }
   else
      printf ("buff=10\n");

   ///singleshot
   echotimer->start (1000, true);
}


void
SopFork::echo ()
{
   bool found = false;
   ///if the current page is within the list, then update data statistics
   for (QWidget * wd = listpage.first (); wd; wd = listpage.next ())
      if (tabwidget->indexOf (wd) == tabwidget->currentPageIndex ()) {
	 write (snstatus->socket (), "s\n", sizeof ("s\n"));
	 found = true;
	 break;
      }
   if (found == false)
      echotimer->start (1000, true);
}
